/*                          UX-Framework                               
 *                                                                 
 *  iZE Co.,Ltd. Copyright 2009 All rights reserved.          
 *  This file is distributed under the terms of the GNU Lesser 
 *  General Public License, described in file LICENSE.                                     
 */
package jp.ize.ux.components;

// {{{ imports
import jp.ize.ux.UXObject;
import jp.ize.ux.UXController;
import jp.ize.ux.UXInteraction;
import jp.ize.ux.UXFocusManager;
import jp.ize.ux.components.UXComponent;
import jp.ize.ux.components.UXComponentResource;
import jp.ize.ux.components.themes.basic.UXSliderResource;
import jp.ize.ux.interactions.UXGeneralInteraction;
import jp.ize.ux.events.UXMouseEvent;
import jp.ize.ux.utils.UXRange;
import jp.ize.ux.states.UXBasicState;
import jp.ize.ux.acts.Act;
import jp.ize.ux.geom.UXSize;
import flash.geom.Rectangle;
import flash.geom.Point;
// }}}
// {{{ enum UXSliderDirection
enum UXSliderDirection
{
	/** 水平方向を表すバリアントです。 */
	HORIZONTAL;
	/** 鉛直方向を表すバリアントです。 */
	VERTICAL;
}
// }}}
// {{{ class UXSliderAct extends Act
/**
 * UXSliderAct クラス<br>
 * UXSliderのデフォルトアクションです。
 */
class UXSliderAct extends Act
{
	// {{{ public function new()
	/**
	 * コンストラクタです。<br>
	 */
	public function new()
	{
		super();
	}
	// }}}
	// {{{ public function uplight() : UXSliderState -> Void
	/**
	 * ボタンをハイライトした時のデフォルトアクションです。
	 */
	public function uplight() : UXSliderState -> Void
	{
		return function( s : UXSliderState ) {
		}
	}
	// }}}
	// {{{ public function downlight() : UXSliderState -> Void
	/**
	 * ボタンのハイライトを解除した時のデフォルトアクションです。
	 */
	public function downlight() : UXSliderState -> Void
	{
		return function( s : UXSliderState ) {
		}
	}
	// }}}
	// {{{ public function focus() : UXSliderState -> Void
	/**
	 * ボタンがフォーカスされた時のデフォルトアクションです。
	 */
	public function focus() : UXSliderState -> Void
	{
		return function( s : UXSliderState ) {
		}
	}
	// }}}
	// {{{ public function unfocus() : UXSliderState -> Void
	/**
	 * ボタンのフォーカスが解除された時のデフォルトアクションです。
	 */
	public function unfocus() : UXSliderState -> Void
	{
		return function( s : UXSliderState ) {
		}
	}
	// }}}
	// {{{ public function disable() : UXSliderState -> Void
	/**
	 * 無効にした時のデフォルトアクションです。
	 */
	public function disable() : UXSliderState -> Void
	{
		return function( s : UXSliderState ) {
		}
	}
	// }}}
	// {{{ public function enable() : UXSliderState -> Void
	/**
	 * 有効にした時のデフォルトアクションです。
	 */
	public function enable() : UXSliderState -> Void
	{
		return function( s : UXSliderState ) {
		}
	}
	// }}}
	// {{{ public function show() : UXSliderState -> Void
	/**
	 * 表示状態になった時のデフォルトアクションです。
	 */
	public function show() : UXSliderState -> Void
	{
		return function( s : UXSliderState ) {
		}
	}
	// }}}
	// {{{ public function hide() : UXSliderState -> Void
	/**
	 * 非表示状態になった時のデフォルトアクションです。
	 */
	public function hide() : UXSliderState -> Void
	{
		return function( s : UXSliderState ) {
		}
	}
	// }}}
}
// }}}
// {{{ class UXSliderState extends UXBasicState
/**
 * UXSliderState クラス<br>
 * UXSliderの現在の状態を表すオブジェクトです。
 */
class UXSliderState extends UXBasicState
{
	// {{{ properties
	// {{{ public var size( default, default ) : UXSize;
	/**
	 * スライダーのサイズです。
	 */
	public var size( default, default ) : UXSize;
	// }}}
	// {{{ public var trac(default, default) : UXComponentResource
	/**
	 * スライダートラック(背景)です。
	 */
	public var trac(default, default) : UXComponentResource;
	// }}}
	// {{{ public var thumb(default, default) : UXComponentResource
	/**
	 * スライダーサムです。
	 */
	public var thumb(default, default) : UXComponentResource;
	// }}}
	// {{{ public var direction( default, default ) : UXSliderDirection
	/**
	 * スライダが水平方向か、鉛直方向かを設定します。
	 */
	public var direction( default, default ) : UXSliderDirection;
	// }}}
	// {{{ public var range( default, default ) : UXRange;
	/**
	 * スライダで設定できる最小値と最大値を設定します。
	 */
	public var range( default, default ) : UXRange;
	// }}}
	// {{{ public var step(default, default) : Float
	/**
	 * 移動の最小単位です。
	 */
	public var step(default, default) : Float;
	// }}}
	// {{{ public var position( default, default ) : Float;
	/**
	 * スライダの現在の値を取得または設定します。
	 */
	public var position( default, default ) : Float;
	// }}}
	// {{{ public var liveDragging( default, default ) : Bool;
	/**
	 * ユーザーがスライダサムをドラッグしている間、SliderChangeInteractionが
	 * 継続的にスライダーが変化したイベントを送出するかどうかを示すブール値を取得または設定します。
	 */
	public var liveDragging( default, default ) : Bool;
	// }}}
	// {{{ public var acts(default, null) : UXSliderAct
	/**
	 * デフォルトの動きです。
	 */
	public var acts(default, null) : UXSliderAct;
	// }}}
	// }}}
	// {{{ public function new( mysize:UXSize, dir:UXSliderDirection ) : Void
	/**
	 * コンストラクタです。
	 */
	public function new( mysize:UXSize, dir:UXSliderDirection ) : Void
	{
		super();
		this.size      = mysize;
		this.direction = dir;
		var res = new UXSliderResource(this,dir);
		this.trac      = res.trac;
		this.thumb     = res.thumb;
		setRange( new UXRange(0,1) );
		acts = new UXSliderAct();
		thumb.addUXEventListener( UXMouseEvent.DOWN, onThumbMouseDown );
		thumb.addUXEventListener( UXMouseEvent.UP,   onThumbMouseUp );
		thumb.addUXEventListener( UXMouseEvent.OVER, onThumbMouseUp );
		thumb.addUXEventListener( UXMouseEvent.OUT,  onThumbMouseUp );
		trac.addUXEventListener(  UXMouseEvent.UP,   onTracMouseUp );
	}
	// }}}
	// {{{ public function onThumbMouseDown( e:Dynamic ) : Void

	public function onThumbMouseDown( e:Dynamic ) : Void
	{
		var bounds = null;
		if ( direction==HORIZONTAL ) {
			var val = size.width-thumb.width+1;
			bounds = new Rectangle( 0, 0, val, 0 );
		} else {
			var val = size.height-thumb.height+1;
			bounds = new Rectangle( 0, 0, 0, val );
		}
		thumb.startDrag( false, bounds );
	}

	// }}}
	// {{{ public function onThumbMouseUp( e:Dynamic ) : Void

	public function onThumbMouseUp( e:Dynamic ) : Void
	{
		thumb.stopDrag();
		if ( direction==HORIZONTAL ) {
			setSliderPosition( thumb.x );
		} else {
			setSliderPosition( thumb.y );
		}
	}

	// }}}
	// {{{ public function onTracMouseUp( e:Dynamic ) : Void

	public function onTracMouseUp( e:Dynamic ) : Void
	{
		var p1 = new Point(e.stageX,e.stageY);
		var p2 = trac.globalToLocal(p1);
		if ( direction==HORIZONTAL ) {
			setSliderPosition( p2.x - thumb.width/2 );
		} else {
			setSliderPosition( p2.y - thumb.height/2 );
		}
	}

	// }}}
	// {{{ public function setRange( r:UXRange ) : Void

	public function setRange( r:UXRange ) : Void
	{
		range = r;
	}

	// }}}
	// {{{ public function setSliderPosition( pos:Float ) : Void

	public function setSliderPosition( pos:Float ) : Void
	{
		var val = 0.0;
		if ( direction==HORIZONTAL ) {
			val = size.width-thumb.width+1;
		} else {
			val = size.height-thumb.height+1;
		}
		var r = new UXRange(0,val);
		if ( r.inValue(pos) ) {
			if ( direction==HORIZONTAL ) {
				thumb.x = pos;
			} else {
				thumb.y = pos;
			}
		} else if ( pos<=r.min ) {
			if ( direction==HORIZONTAL ) {
				thumb.x = 0;
			} else {
				thumb.y = 0;
			}
		} else if ( pos>=r.max ) {
			if ( direction==HORIZONTAL ) {
				thumb.x = size.width - thumb.width + 1;
			} else {
				thumb.y = size.height - thumb.height + 1;
			}
		}
		cast(target,UXSlider).ctrl.trigger("Changed");
	}

	// }}}
	// {{{ public function getSliderPosition() : Float

	public function getSliderPosition() : Float
	{
		if ( direction==HORIZONTAL ) {
			return thumb.x;
		} else {
			return thumb.y;
		}
	}

	// }}}
	// {{{ public function getSliderValue() : Float

	public function getSliderValue() : Float
	{
		var val = size.width-thumb.width;
		return getSliderPosition() / val * (range.max-range.min) + range.min;
	}

	// }}}
	// {{{ public function refresh() : Void

	public function refresh() : Void
	{
		if ( range!=null ) {
			var v = getSliderValue();
			trac.normal();
			thumb.normal();
			setSliderPosition( v * range.max );
		}
	}

	// }}}
}
// }}}

// {{{ class UXSlider extends UXComponent<UXSliderState>
/**
 * UXSliderクラス<br>
 * ユーザが指定された区間内でノブをスライドすることによりグラフィカルに値を選択できるようにするコンポーネントです。<br>
 *
 * @author		iZE Co., Ltd.<br>
 * @version		$Id$<br>
 */
class UXSlider extends UXComponent<UXSliderState>
{
	// {{{ public function new( size:UXSize, ?dir : UXSliderDirection )
	/**
	 * コンストラクタです。引数で指定した方向のスライダーを作ります。デフォルト値はHORIZONTALです。
	 */
	public function new( size:UXSize, ?dir : UXSliderDirection )
	{
		if (dir == null) dir = UXSliderDirection.HORIZONTAL;
		state = new UXSliderState(size,dir);
		state.target = this;
		ctrl = new UXController<UXSliderState>( state );
		super(ctrl);
		addUXChild(state.trac);
		addUXChild(state.thumb);
		ctrl.addInteraction( new UXSliderChangedInteraction() );
	}
	// }}}
	// {{{ public function refreshResource() : Void
	/**
	 * ボタンに対するグローバルなリソースを再取得する関数です。
	 */
	public function refreshResource() : Void
	{
	}
	// }}}
	// {{{ public function update( updator : UXSliderState -> Void ) : Void
	/**
	 * このコンポーネントの状態を直接変更するメソッドです。状態のどんな操作も可能になるので、
	 * このメソッドの使用には注意が必要です。
	 */
	public function update( updator : UXSliderState -> Void ) : Void
	{
		updator( state );
	}
	// }}}
}
// }}}

// {{{ class UXSliderChangedInteraction extends UXInteraction<UXSliderState>
/**
 * UXSliderChangInteraction クラス<br>
 * スクロールに対応するデフォルトインタラクションです。
 */
class UXSliderChangedInteraction extends UXGeneralInteraction<UXSliderState>
{
	// {{{ public function new() : Void
	/**
	* コンストラクタ
	*/
	public function new() : Void
	{
		super("Changed");
		setActSequentialMode(true);
		this.judge = function(s) {
			return s.enabled;
		}
	}

	// }}}
}
// }}}
